package cn.s1995.sloth.bizs.aspect;


import cn.s1995.sloth.bizs.constant.RedisKeyCst;
import cn.s1995.sloth.bizs.service.UserVisitorRecordService;
import cn.s1995.sloth.bizs.util.RedisUtil;
import cn.s1995.sloth.common.core.constant.SecurityConstants;
import cn.s1995.sloth.common.security.service.SlothUser;
import cn.s1995.sloth.common.security.util.SecurityUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * UserVisitorAspect
 *
 * @author Lex
 * @description 用户访问切面
 * @date 2024-05-05 18:03
 */
@Slf4j
@Aspect
@Order(-15)
@Component
public class UserVisitorAspect {

    /**
     * 客户端：app
     */
    public static final String CLIENT_APP = "app";
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private UserVisitorRecordService userVisitorRecordService;


    /**
     * 切点-定义一个切入点，可以是一个规则表达式，比如下例中某个 package 下的所有函数，也可以是一个注解等
     * <p>
     * execution() 为表达式主体
     * 第一个 * 号的位置：表示返回值类型，* 表示所有类型
     * 包名：表示需要拦截的包名，后面的两个句点表示当前包和当前包的所有子包，com.itcodai.course09.controller 包、子包下所有类的方法
     * 第二个 * 号的位置：表示类名，* 表示所有类
     * *(..) ：这个星号表示方法名，* 表示所有的方法，后面括弧里面表示方法的参数，两个句点表示任何参数
     */
    @Pointcut("execution(* cn.s1995.sloth.*.controller..*.*(..))")
    public void aspect() {
    }

    /**
     * 环绕-在切入点前后切入内容，并自己控制何时执行切入点自身的内容(不与@AfterThrowing混用)
     *
     * @param point
     * @return
     * @throws Throwable
     */
    @Around("aspect()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        SlothUser user = SecurityUtils.getUser();
        if (user != null
                && user.getId() != null
                && CLIENT_APP.equals(user.getAttribute(SecurityConstants.CLIENT_ID))
                && !redisUtil.hasKey(RedisKeyCst.USER_VISITOR + user.getId())
        ) {
            log.debug("添加用户访问记录 -> uid:{}", user.getId());
            // 添加用户访问记录
            userVisitorRecordService.addUserVisitor(user.getId());
        }
        return point.proceed();
    }


}
